---
title: Emit Events
description:
  Learn how to emit events in Anchor programs using emit! and emit_cpi! macros.
---

## Examples

Anchor provides two macros for emitting events in your programs:

1. `emit!()` - Emits events directly to program logs. This is the simpler,
   though program logs may be truncated by data providers in some cases
2. `emit_cpi!()` - Emits events through a Cross Program Invocation (CPI) by
   including the event data in the instruction data.

<Callout type="info">

The `emit_cpi()` approach was introduced an alternative to program logs, which
can sometimes be truncated by data providers. While CPI instruction data is less
likely to be truncated, this approach does incur additional compute costs from
the Cross Program Invocation.

</Callout>

<Callout type="info">

For more robust solutions for events, consider geyser gRPC services by
[Triton](https://docs.triton.one/project-yellowstone/dragons-mouth-grpc-subscriptions)
or [Helius](https://docs.helius.dev/data-streaming/geyser-yellowstone).

</Callout>

### `emit`

The
[`emit!()`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/event/src/lib.rs#L101-L109)
macro provides a way to emit events through program logs. When called, it:

1. Uses the
   [`sol_log_data()`](https://github.com/anza-xyz/agave/blob/c2b350023ba849d1b33142592264aaa51fcb7f1e/sdk/program/src/log.rs#L115-L124)
   syscall to write the data to program logs
2. Encodes the event data as a
   [base64 string](https://github.com/anza-xyz/agave/blob/c2b350023ba849d1b33142592264aaa51fcb7f1e/program-runtime/src/stable_log.rs#L46-L61)
   prefixed with `Program Data:`

To receive emitted events in your client application, use the
[`addEventListener()`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/ts/packages/anchor/src/program/event.ts#L74-L123)
method. This method automatically
[parses and decodes](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/ts/packages/anchor/src/program/event.ts#L232-L253)
event data from the program logs.

Example usage:

<Tabs items={["Program", "Client"]}>
<Tab value="Program">

```rust title="lib.rs"
use anchor_lang::prelude::*;

declare_id!("8T7MsCZyzxboviPJg5Rc7d8iqEcDReYR2pkQKrmbg7dy");

#[program]
pub mod event {
    use super::*;

    pub fn emit_event(_ctx: Context<EmitEvent>, input: String) -> Result<()> {
        // [!code word:emit!]
        // [!code highlight]
        emit!(CustomEvent { message: input });
        Ok(())
    }
}

#[derive(Accounts)]
pub struct EmitEvent {}

// [!code highlight:4]
#[event]
pub struct CustomEvent {
    pub message: String,
}
```

</Tab>
<Tab value="Client">

```ts title="test.ts"
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { Event } from "../target/types/event";

describe("event", () => {
  // Configure the client to use the local cluster.
  anchor.setProvider(anchor.AnchorProvider.env());

  const program = anchor.workspace.Event as Program<Event>;

  it("Emits custom event", async () => {
    // Set up listener before sending transaction
    // [!code word:addEventListener]
    // [!code highlight:4]
    const listenerId = program.addEventListener("customEvent", event => {
      // Do something with the event data
      console.log("Event Data:", event);
    });

    // Message to be emitted in the event
    const message = "Hello, Solana!";
    // Send transaction
    await program.methods.emitEvent(message).rpc();

    // Remove listener
    await program.removeEventListener(listenerId);
  });
});
```

</Tab>
</Tabs>

<!-- cspell:disable -->

The following is the output of the program logs. The event data is base64
encoded as `Zb1eU3aiYdwOAAAASGVsbG8sIFNvbGFuYSE=`.

```shell title="Program Logs"
Log Messages:
  Program 8T7MsCZyzxboviPJg5Rc7d8iqEcDReYR2pkQKrmbg7dy invoke [1]
  Program log: Instruction: EmitEvent
  Program data: Zb1eU3aiYdwOAAAASGVsbG8sIFNvbGFuYSE=
  Program 8T7MsCZyzxboviPJg5Rc7d8iqEcDReYR2pkQKrmbg7dy consumed 1012 of 200000 compute units
  Program 8T7MsCZyzxboviPJg5Rc7d8iqEcDReYR2pkQKrmbg7dy success
```

<!-- cspell:enable -->

<Callout type="info">
  Ensure the RPC provider you use does not truncate the program logs from the
  transaction data.
</Callout>

### `emit_cpi`

The
[`emit_cpi!()`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/event/src/lib.rs#L155-L195)
macro emits events through Cross Program Invocations (CPIs) to the program
itself. The event data is encoded and included in the CPI's instruction data
(instead of program logs).

To emit events through CPIs, you need to enable the `event-cpi` feature in your
program's `Cargo.toml`:

```toml title="Cargo.toml"
[dependencies]
anchor-lang = { version = "0.32.1", features = ["event-cpi"] }
```

Example usage:

<Tabs items={["Program", "Client"]}>
<Tab value="Program">

```rust title="lib.rs"
use anchor_lang::prelude::*;

declare_id!("2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1");

#[program]
pub mod event_cpi {
    use super::*;

    pub fn emit_event(ctx: Context<EmitEvent>, input: String) -> Result<()> {
        // [!code word:emit_cpi!]
        // [!code highlight]
        emit_cpi!(CustomEvent { message: input });
        Ok(())
    }
}

// [!code highlight]
#[event_cpi]
#[derive(Accounts)]
pub struct EmitEvent {}

// [!code highlight:4]
#[event]
pub struct CustomEvent {
    pub message: String,
}
```

</Tab>
<Tab value="Client">

```ts title="test.ts"
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { EventCpi } from "../target/types/event_cpi";

describe("event-cpi", () => {
  // Configure the client to use the local cluster.
  anchor.setProvider(anchor.AnchorProvider.env());
  const program = anchor.workspace.EventCpi as Program<EventCpi>;

  it("Emits custom event", async () => {
    const message = "Hello, Solana!";
    const transactionSignature = await program.methods.emitEvent(message).rpc();

    // Wait for the transaction to be confirmed
    await program.provider.connection.confirmTransaction(
      transactionSignature,
      "confirmed",
    );

    // Fetch the transaction data
    // [!code highlight:4]
    const transactionData = await program.provider.connection.getTransaction(
      transactionSignature,
      { commitment: "confirmed" },
    );

    // Decode the event data from the CPI instruction data
    // [!code highlight:4]
    const eventIx = transactionData.meta.innerInstructions[0].instructions[0];
    const rawData = anchor.utils.bytes.bs58.decode(eventIx.data);
    const base64Data = anchor.utils.bytes.base64.encode(rawData.subarray(8));
    const event = program.coder.events.decode(base64Data);
    console.log(event);
  });
});
```

</Tab>
</Tabs>

The
[`event_cpi`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/event/src/lib.rs#L228-L237)
attribute must be added to the `#[derive(Accounts)]` struct for the instruction that emits events using the `emit_cpi!()` macro. This attribute
[automatically includes additional accounts](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/syn/src/parser/accounts/event_cpi.rs#L28-L70)
that are required for the self CPI.

```rust title="lib.rs"
// [!code highlight]
#[event_cpi]
#[derive(Accounts)]
pub struct RequiredAccounts {
  // --snip--
}
```

To get the emitted event data in your client application, you need to fetch the
transaction using the transaction signature and parse the event data from the
CPI instruction data.

```ts title="test.ts"
// 1. Fetch the full transaction data using the transaction signature
const transactionData = await program.provider.connection.getTransaction(
  transactionSignature,
  { commitment: "confirmed" },
);

// 2. Extract the CPI (inner instruction) that contains the event data
const eventIx = transactionData.meta.innerInstructions[0].instructions[0];

// 3. Decode the event data
const rawData = anchor.utils.bytes.bs58.decode(eventIx.data);
const base64Data = anchor.utils.bytes.base64.encode(rawData.subarray(8));
const event = program.coder.events.decode(base64Data);
console.log(event);
```

Below is an example transaction showing how event data appears in the
transaction details. When using `emit_cpi!()`, the event data is encoded and
included in the `data` field of an inner instruction (CPI).

In the example transaction below, the encoded event data is
`"data": "6AJcBqZP8afBKheoif1oA6UAiLAcqYr2RaR33pFnEY1taQp"` in the
`innerInstructions` array.

<!-- cspell:disable -->

```shell title="Transaction Data"
{
  "blockTime": 1735854530,
  "meta": {
    "computeUnitsConsumed": 13018,
    "err": null,
    "fee": 5000,
    "innerInstructions": [
      {
        "index": 0,
        "instructions": [
          {
            "accounts": [
              1
            ],
            "data": "6AJcBqZP8afBKheoif1oA6UAiLAcqYr2RaR33pFnEY1taQp",
            "programIdIndex": 2,
            "stackHeight": 2
          }
        ]
      }
    ],
    "loadedAddresses": {
      "readonly": [],
      "writable": []
    },
    "logMessages": [
      "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 invoke [1]",
      "Program log: Instruction: EmitEvent",
      "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 invoke [2]",
      "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 consumed 5000 of 192103 compute units",
      "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 success",
      "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 consumed 13018 of 200000 compute units",
      "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 success"
    ],
    "postBalances": [
      499999999999995000,
      0,
      1141440
    ],
    "postTokenBalances": [],
    "preBalances": [
      500000000000000000,
      0,
      1141440
    ],
    "preTokenBalances": [],
    "rewards": [],
    "status": {
      "Ok": null
    }
  },
  "slot": 3,
  "transaction": {
    "message": {
      "header": {
        "numReadonlySignedAccounts": 0,
        "numReadonlyUnsignedAccounts": 2,
        "numRequiredSignatures": 1
      },
      "accountKeys": [
        "4kh6HxYZiAebF8HWLsUWod2EaQQ6iWHpHYCz8UcmFbM1",
        "2brZf9PQqEvv17xtbj5WNhZJULgVZuLZT6FgH1Cqpro2",
        "2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1"
      ],
      "recentBlockhash": "2QtnU35RXTo7uuQEVARYJgWYRYtbqUxWQkK8WywUnVdY",
      "instructions": [
        {
          "accounts": [
            1,
            2
          ],
          "data": "3XZZ984toC4WXCLkxBsLimpEGgH75TKXRJnk",
          "programIdIndex": 2,
          "stackHeight": null
        }
      ],
      "indexToProgramIds": {}
    },
    "signatures": [
      "3gFbKahSSbitRSos4MH3cqeVv2FiTNaLCuWaLPo6R98FEbHnTshoYxopGcx74nFLqt1pbZK9i8dnr4NFXayrMndZ"
    ]
  }
}
```

<!-- cspell:enable -->

<Callout type="info">
  Currently, event data emitted through CPIs cannot be directly subscribed to.
  To access this data, you must fetch the complete transaction data and manually
  decode the event information from the instruction data of the CPI.
</Callout>
